package com.lsh.oms.core.service.order;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.lsh.atp.api.model.base.Item;
import com.lsh.atp.api.model.hold.HoldRequest;
import com.lsh.atp.api.model.hold.HoldResponse;
import com.lsh.atp.api.service.hold.IHoldRpcService;
import com.lsh.base.common.model.CommonResult;
import com.lsh.oms.api.model.order.create.MisOrderHeadDTO;
import com.lsh.oms.core.constant.AtpConstant;
import com.lsh.oms.core.constant.ReturnCode;
import com.lsh.oms.core.enums.OrderStatus;
import com.lsh.oms.core.enums.PoOrderFlag;
import com.lsh.oms.core.enums.YN;
import com.lsh.oms.core.exception.BusinessException;
import com.lsh.oms.core.model.order.OrderDetail;
import com.lsh.oms.core.model.order.OrderHead;
import com.lsh.oms.core.model.order.OrderHeadExt;
import com.lsh.oms.core.utils.HttpUtils;
import com.lsh.oms.core.utils.sign.MessageDigestEnum;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.Consts;
import org.apache.http.Header;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.*;

/**
 * Project Name: AbstractOrderCreateService
 * 北京链商电子商务有限公司
 *
 * @author wangliutao
 * Date: 18/5/10
 * Package Name: com.lsh.oms.core.service.order
 * Description:
 * @author peter
 */
@Component
public class OrderCreateValidateService {

    private static Logger logger = Logger.getLogger(OrderCreateValidateService.class);

    @Autowired
    private IHoldRpcService holdRpcService;

    @Autowired
    private OrderQueryService orderQueryService;

    @Value("${data.risk.host}")
    private String riskDataUrl;

    @Value("${data.risk.rule}")
    private String ruleId;

    @Value("${data.risk.token}")
    private String DATA_RISK_API_TOKEN;


    public CommonResult validateAll(OrderHead head, MisOrderHeadDTO misOrderHeadDTO, String logSign) {
        HashMap<String, Long> times = new HashMap<>();

        String misOrderNo = head.getMisOrderNo();
        OrderHead oh = new OrderHead();
        oh.setMisOrderNo(misOrderNo);
        oh.setValid(YN.Y.getValue());
        long checkRefCodeTsS = System.currentTimeMillis();
        int misOrderNoExist = orderQueryService.count(oh);
        long checkRefCodeTsE = System.currentTimeMillis();
        if (misOrderNoExist > 0) {
            return new CommonResult<>(ReturnCode.REQUEST_FAIL, "misOrderNo is exist!", Collections.singletonList(misOrderNo));
        }
        times.put("checkRefCodeTs", Long.valueOf(checkRefCodeTsE - checkRefCodeTsS));

        //风控校验 TODO 2019-09-06 关闭风控
//        long checkRiskTsS = System.currentTimeMillis();
//        CommonResult<List<String>> riskRet = this.checkByRisk(head, misOrderHeadDTO, logSign);
//        long checkRiskTsE = System.currentTimeMillis();
//        if (!CommonResult.SUCCESS.equals(riskRet.getCode())) {
//            return riskRet;
//        }
//        times.put("checkRiskTs", Long.valueOf(checkRiskTsE - checkRiskTsS));

        return new CommonResult(CommonResult.SUCCESS, "success", times);
    }

    /**
     * 风控校验
     *
     * @param head
     * @param misOrderHeadDTO
     * @return
     */
    private CommonResult<List<String>> checkByRisk(OrderHead head, MisOrderHeadDTO misOrderHeadDTO, String mislogSign) {
        StringBuilder logSign = this.buildLogSign(head, mislogSign);
        int logSignIndex = logSign.length();
        Long orderCode = head.getOrderCode();
        JSONObject riskData = null;
        boolean riskStatus = false;
        try {

            String params = this.genParams4RiskRequest(head, misOrderHeadDTO);
            StringEntity entity = new StringEntity(params, org.apache.http.entity.ContentType.create(URLEncodedUtils.CONTENT_TYPE, Consts.UTF_8));
            Header[] headers = {new BasicHeader("api-version", "1.1"), new BasicHeader("platform", "oms"), new BasicHeader("sign", "md5")};
            String riskUrl = riskDataUrl + "/risk/risk_proxy";

            JSONObject riskResp = null;
            long start = System.currentTimeMillis();
            logSign.setLength(logSignIndex);
            logger.info(logSign.append("大数据风控服务参数：").append(params).toString());
            String content = HttpUtils.post(riskUrl, entity, true, headers).getData();
            logSign.setLength(logSignIndex);
            logger.info(logSign.append("大数据风控服务返回：").append(content).toString());
            logSign.setLength(logSignIndex);
            logger.info(logSign.append("大数据风控服务耗时：").append((System.currentTimeMillis() - start)).append("ms").toString());
            if (StringUtils.isNotEmpty(content)) {
                riskResp = JSON.parseObject(content);
            }
            //异常时默认通过,不影响用户下单
            if (riskResp == null) {
                logSign.setLength(logSignIndex);
                logger.info(logSign.append("调用大数据风控异常,订单号:").append(orderCode).append(",").toString());
            } else {
                Integer errorCode = riskResp.getInteger("error_code");
                if (errorCode.equals(-1)) {
                    return new CommonResult<>(ReturnCode.RISK_NO_RULEID, "风控规则ID为空", null);
                }
                riskData = JSON.parseObject(riskResp.getString("data"));
                if (errorCode.equals(0)) {
                    if (riskData.getInteger("code").equals(1001)) {
                        return new CommonResult<>(ReturnCode.RISK_NO_PASS, "风控验证拒绝通过", null);
                    }
                    if (riskData.getInteger("code").equals(1008)) {
                        riskStatus = true;
                    }
                }
            }
        } catch (Throwable e) {//异常时默认通过,不影响用户下单
            logSign.setLength(logSignIndex);
            logger.error(logSign.append("调用大数据风控异常").append(e.getMessage()).toString(), e);
        }
        if (riskData == null) {
            riskData = new JSONObject();
        }
        JSONObject extObj;
        String ext = head.getExt();
        if (StringUtils.isEmpty(ext)) {
            extObj = new JSONObject();
        } else {
            extObj = JSON.parseObject(ext);
        }
        extObj.put("risk_data", riskData);
        head.setExt(extObj.toJSONString());

        String poOrderFlag = misOrderHeadDTO.getPoOrderFlag();
        if (StringUtils.isBlank(poOrderFlag)) {
            poOrderFlag = PoOrderFlag.PO_NO_ORDER.getType();
        }

        if (riskStatus && head.getPayType() == 1 && !poOrderFlag.equals(PoOrderFlag.PRE_ORDER.getType())) {
            head.setIsMp(YN.N.getValue());
            head.setOrderStatus(OrderStatus.ORDER_NO_EDIT.getIndex());
        }
        return CommonResult.success(null);
    }

    /**
     * 柱状风控校验参数
     *
     * @param head
     * @return
     */
    private String genParams4RiskRequest(OrderHead head, MisOrderHeadDTO misOrderHeadDTO) {
        List<OrderDetail> details = head.getDetails();
        JSONArray skuList = new JSONArray(details.size());
        for (OrderDetail detail : details) {
            String[] params = new String[3];
            params[0] = ObjectUtils.toString(detail.getGoodsCode());
            params[1] = ObjectUtils.toString(detail.getQuantity());
            params[2] = ObjectUtils.toString(detail.getOriginalPrice());
            skuList.add(params);
        }
        OrderHeadExt headExt = head.getExtObject();
        List<BasicNameValuePair> pairs = new ArrayList<>(12);
        pairs.add(new BasicNameValuePair("address_id", head.getAddressCode().toString()));
        pairs.add(new BasicNameValuePair("cash_coupon_list", this.getCouponInfo4RiskParams(headExt.getCashCouponInfo()).toJSONString()));
        pairs.add(new BasicNameValuePair("coupon_list", this.getCouponInfo4RiskParams(headExt.getCouponInfo()).toJSONString()));
        pairs.add(new BasicNameValuePair("device_id", ObjectUtils.toString(misOrderHeadDTO.getDeviceId())));
        pairs.add(new BasicNameValuePair("ip", headExt.getIp().toString()));
        pairs.add(new BasicNameValuePair("mobile", ObjectUtils.toString(misOrderHeadDTO.getUsername())));
        pairs.add(new BasicNameValuePair("order_money", headExt.getOriginMoney().toString()));
        pairs.add(new BasicNameValuePair("rule_id", this.ruleId));
        pairs.add(new BasicNameValuePair("sku_list", skuList.toJSONString()));
        pairs.add(new BasicNameValuePair("user_id", head.getUserCode().toString()));
        pairs.add(new BasicNameValuePair("zone_id", head.getRegionCode().toString()));
        String params = URLEncodedUtils.format(pairs, Consts.UTF_8);

        String sign = MessageDigestEnum.SHA1.toString(new StringBuilder(params).append(DATA_RISK_API_TOKEN).toString());
        return new StringBuilder(params).append("&sign=").append(sign).toString();
    }

    /**
     * 组装风控请求参数优惠信息
     *
     * @param json
     * @return
     */
    private JSONArray getCouponInfo4RiskParams(String json) {
        JSONArray couponInfo = JSON.parseArray(json);
        JSONArray array = new JSONArray(couponInfo.size());
        for (int i = 0; i < couponInfo.size(); i++) {
            JSONObject info = couponInfo.getJSONObject(i).getJSONObject("info");
            String[] params = new String[2];
            params[0] = ObjectUtils.toString(info.get("coupon_id"));
            params[1] = ObjectUtils.toString(info.get("coupon_value"));
            array.add(params);
        }
        return array;
    }

    /**
     * 库存可用心检查、扣减
     *
     * @param head
     * @param misLogSign
     * @return
     */
    public CommonResult<List<String>> checkAndSubtractStock(OrderHead head, String misLogSign) {
        HoldRequest request = new HoldRequest();
        request.setZoneCode(head.getRegionCode().toString());
        request.setChannel(AtpConstant.ATP_CHANNEL_CODE);
        request.setSequence(head.getOrderCode().toString());
        request.setItems(this.genItems4AtpRequest(head.getDetails()));
        request.setHoldEndTime(System.currentTimeMillis() / 1000 + 10000000);
        request.setIsDecrease(1);
        // TODO 2019-01-17 peter 暂定
        request.setAddressId(head.getAddressCode() + "");
//        request.setUserId(head.getUserCode() + "");
        request.setVenderId(head.getVenderId());

        StringBuilder logSign = this.buildLogSign(head, misLogSign);
        int logSignIndex = logSign.length();

        logSign.setLength(logSignIndex);
        logger.info(logSign.append("创建订单ATP入参：").append(JSON.toJSONString(request)).toString());
        long start = System.currentTimeMillis();
        HoldResponse response = this.holdRpcService.preHold(request);
        long end = System.currentTimeMillis();
        logSign.setLength(logSignIndex);
        logger.info(logSign.append("创建订单ATP返回：").append(JSON.toJSONString(response)));
        logSign.setLength(logSignIndex);
        logger.info(logSign.append("创建订单atp耗时：").append(end - start).append("ms").toString());

        if (response == null) {
            return new CommonResult<>(ReturnCode.REQUEST_ATP_ERROR_CREATE_ORDER, "库存返回为空", null);
        }
        Integer status = response.getStatus();
        if (AtpConstant.ATP_INVENTORY_SHORTAGE.equals(status)) {
            String respStr = "";
            List<Item> atpItems = response.getItemList();
            if (atpItems == null || atpItems.size() == 0) {
                respStr = "结算商品可购买数量发生变化，请返回购物车修改。";
            }
            Item atpItem = atpItems.get(0);
            if (atpItem == null) {
                return new CommonResult<>(ReturnCode.REQUEST_ATP_ERROR_CREATE_ORDER, respStr, null);
            }
            BigDecimal atpQty = atpItem.getQty();
            if (atpQty == null || atpQty.compareTo(BigDecimal.ZERO) == 0) {
                respStr = "部分商品失效，导致订单金额发生变化，请返回购物车查看。";
            }
            return new CommonResult<>(ReturnCode.REQUEST_ATP_ERROR_INVENTORY_SHORTAGE, respStr, response.getSkuIdList());
        }
        if (!status.equals(0) || StringUtils.isEmpty(response.getHoldId())) {
            List<String> respList = new ArrayList<>();
            String str = "创建订单 -- RPC 调用ATP失败";
            respList.add(str);
            return new CommonResult<>(ReturnCode.REQUEST_ATP_ERROR_CREATE_ORDER, str, respList);
        }
        head.setAtpFlowCode(response.getHoldId());
        return CommonResult.success(null);
    }

    /**
     * 组装ATP请求items
     *
     * @param details
     * @return
     */
    private List<Item> genItems4AtpRequest(List<OrderDetail> details) {
        Map<String, Map<String, Item>> map = new HashMap<>(details.size() + 20);
        List<Item> items = new ArrayList<>(details.size());
        for (OrderDetail detail : details) {

            String ext = detail.getDetailExt();
            JSONObject extJson = JSON.parseObject(ext);
            Integer providerId = extJson.getInteger("providerId");

            if (providerId == null) {
                throw new BusinessException("1002005", "providerId 不能为空");
            }

            Long skuCode = detail.getSkuCode();
            BigDecimal skuQty = detail.getQuantity().multiply(detail.getGoodsSaleUnit());
            String itemType;
            //赠品
            if (AtpConstant.ATP_ITEM_TYPE_INT_2.equals(detail.getType())) {
                itemType = AtpConstant.ATP_ITEM_TYPE_2;
            } else {
                itemType = AtpConstant.ATP_ITEM_TYPE_1;
            }
            Map<String, Item> itemMap = map.get(itemType);
            if (itemMap == null) {
                itemMap = new HashMap<>();
                map.put(itemType, itemMap);
            }
            String splitkey = skuCode + ":" + providerId;
            Item item = itemMap.get(splitkey);
            if (item == null) {
                item = new Item();
                item.setItemId(skuCode);
                item.setQty(skuQty);
                item.setSupplyMarket(providerId);
                item.setItemType(itemType);
                items.add(item);
                itemMap.put(splitkey, item);
            } else {
                item.setQty(skuQty.add(item.getQty()));
            }
        }

        return items;
    }

    /**
     * @param head
     * @param mislogSign
     * @return
     */
    private StringBuilder buildLogSign(OrderHead head, String mislogSign) {
        StringBuilder builder = new StringBuilder(mislogSign);
        builder.append(" 创建订单_").append(head.getMisOrderNo()).append("_").append(head.getOrderCode()).append("：");

        return builder;
    }
}
